<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { Prev, Next } from '@/icons'
import type { StyleValue } from 'vue'
type ChangeIndexType = 'left' | 'right' | number | 'auto'

const xOffsetStep = 100
const scaleStep = 0.6
const opacityStep = 0.5
const timerGap = 3000

const props = defineProps({
  imagesList: {
    type: Array<string>,
    default: () => []
  }
})
const emits = defineEmits<{
  imageChange: [image: HTMLImageElement]
}>()

let index = ref<number>(0)
let timer = ref<number | null>(null)
let imageRef = ref<HTMLImageElement[] | null>(null)
const height = computed(() => {
  return window.innerWidth / 3 + 'px'
})

function getImageStyle(i: number): StyleValue {
  const sign = Math.sign(i - index.value)
  let offsetX = 0
  let rotateYValue = 0
  if (i === index.value) {
    offsetX = (i - index.value) * xOffsetStep
  } else {
    offsetX = (i - index.value) * xOffsetStep + xOffsetStep * sign
    rotateYValue = 45 * -sign
  }
  const translateX = `translateX(${offsetX}px)`
  const scale = `scale(${scaleStep ** Math.abs(i - index.value)})`
  const rotateY = `rotateY(${rotateYValue}deg)`
  return {
    transform: `${translateX} ${scale} ${rotateY}`,
    opacity: opacityStep ** Math.abs(index.value - i)
  }
}
function onChangeIndex(type: ChangeIndexType) {
  const oldIndex = index.value
  if (type === 'left') {
    if (index.value !== 0) {
      index.value--
    } else {
      index.value = props.imagesList.length - 1
    }
  } else if (type === 'right' || type === 'auto') {
    if (index.value < props.imagesList.length - 1) {
      index.value++
    } else {
      index.value = 0
    }
  } else {
    index.value = type
  }
  if (type !== 'auto' && oldIndex !== index.value) {
    clearTimer()
    setTimeout(() => {
      startTimer()
    }, timerGap)
  }
  emits('imageChange', imageRef.value![index.value])
}
function startTimer() {
  if (timer.value === null) {
    timer.value = setInterval(() => {
      onChangeIndex('auto')
    }, timerGap)
  }
}
function clearTimer() {
  if (timer.value !== null) {
    clearInterval(timer.value)
    timer.value = null
  }
}

onMounted(() => {
  startTimer()
})
onUnmounted(() => {
  if (timer.value !== null) clearTimer()
})
</script>

<template>
  <div class="--carousel-container">
    <div class="prev-button button-box" @click="onChangeIndex('left')">
      <Prev />
    </div>
    <div class="image-box">
      <div
        class="image-item"
        :style="{
          zIndex: props.imagesList.length - Math.abs(index - i)
        }"
        v-for="(item, i) in props.imagesList"
        :key="i"
      >
        <img
          crossorigin="anonymous"
          ref="imageRef"
          :style="getImageStyle(i)"
          @click="onChangeIndex(i)"
          :src="item"
          alt="pic"
          :data-index="i"
        />
      </div>
    </div>
    <div class="next-button button-box" @click="onChangeIndex('right')">
      <Next />
    </div>
  </div>
</template>

<style scoped lang="scss">
.--carousel-container {
  width: 100vw;
  padding: 0 20px;
  display: flex;
  font-size: 0;
  user-select: none;
  gap: 12px;
  .image-box {
    flex: 1;
    position: relative;

    .image-item {
      position: absolute;
      left: 50%;
      top: 0;
      transform: translateX(-50%);
      transition: all 0.3s;
      perspective: 1000px;
      img {
        transition: all 0.3s;
        cursor: pointer;
      }
    }
  }

  .button-box {
    --bg-color: #f5f5f5;
    --bg-hover-color: #f1f1f1;
    --shadow-color: #e6e6e6;
    --shadow-y: 5px;
    --shadow-y-active: 1px;

    position: relative;
    z-index: 999;
    display: flex;
    cursor: pointer;
    height: v-bind(height);
    flex-direction: column;
    justify-content: center;
    background: var(--bg-color);
    &:hover {
      background: var(--bg-hover-color);
    }
  }
}
</style>
